
package lipengfei.botaiframework.mybatisplus.extend.interceptor;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.cglib.proxy.Enhancer;

import cn.hutool.core.util.StrUtil;
import lipengfei.botaiframework.mybatisplus.extend.lazy.LazyloadFactory;
import lipengfei.botaiframework.mybatisplus.extend.utils.CountSqlParser;
import lipengfei.botaiframework.mybatisplus.extend.utils.MSUtils;

/**
 * myabtis 的拦截器
 * @author  lipf
 *
 * */
@Intercepts(
    {
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
    }
)
public class ExecutorQueryInterceptor implements Interceptor {


    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
        RowBounds rowBounds = (RowBounds) args[2];
        ResultHandler resultHandler = (ResultHandler) args[3];
        Executor executor = (Executor) invocation.getTarget();
        CacheKey cacheKey;
        BoundSql boundSql;
        //由于逻辑关系，只会进入一次
        if(args.length == 4){
            //4 个参数时
            boundSql = ms.getBoundSql(parameter);
            cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
        } else {
            //6 个参数时
            cacheKey = (CacheKey) args[4];
            boundSql = (BoundSql) args[5];
        }
        //拦截自定义扩展的方法
        String msId=ms.getId();
        if(StrUtil.endWith(msId, ".findOne")) {
        	 String newMsId=msId.replace(".findOne", ".findList");
             MappedStatement newMs = ms.getConfiguration().getMappedStatement(newMsId);
             BoundSql newBoundSql = newMs.getSqlSource().getBoundSql(parameter);
             List<Object> resList= executor.query(newMs, parameter, rowBounds, resultHandler, cacheKey, newBoundSql);
             if(resList!=null&&resList.size()>1) {
             	throw new Exception("findOne方法返回了多条符合条件的数据");
             }
     		return resList;
        	
        }
        if(StrUtil.endWith(msId, ".findCount")) {
          	 String newMsId=msId.replace(".findCount", ".findList");
               MappedStatement newMs = ms.getConfiguration().getMappedStatement(newMsId);
               BoundSql newBoundSql = newMs.getSqlSource().getBoundSql(parameter);
               String countSql=	new CountSqlParser().getSimpleCountSql(newBoundSql.getSql());
               BoundSql countBoundSql = new BoundSql(ms.getConfiguration(),countSql,newBoundSql.getParameterMappings(),newBoundSql.getParameterObject());
               MappedStatement countMs= MSUtils.newCountMappedStatement(ms, newMsId);
               List<Object> resList= executor.query(countMs, parameter, rowBounds, resultHandler, cacheKey, countBoundSql);

               if(resList!=null&&resList.size()>1) {
               	throw new Exception("findOne方法返回了多条符合条件的数据");
               }
               
       		return resList;
          	
          }
        
        Object object= invocation.proceed();
        List<?> objItemList=(List<?>)object;
        List<Object> proxyObjectList = new ArrayList<Object>();
		for(Object objItem:objItemList) {
			if(!Modifier.isFinal(objItem.getClass().getModifiers())) {
				LazyloadFactory intercepter=new LazyloadFactory(objItem);       
				Object proxyObject=Enhancer.create(objItem.getClass(),intercepter);
				proxyObjectList.add(proxyObject);
			}			
		}
      if(proxyObjectList.size()==0) {
    	  return  object;
      }else {
    	  return proxyObjectList;
      }
       
    }

    
    

    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }


    public void setProperties(Properties properties) {
    }

   
}
